<?php
namespace App\Controller;

use App\Common;
use Helper\LBS;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;

class LBSController extends Controller
{
    // 获取探霸所连基站信息的命令
    const GET_LBS_LOCATION = 'getlbslocbase';
    // 获取探霸所在位置信息的命令
    const GET_TB_LOCATION = 'getdeviceloc';

    // 探霸信息缓存时间
    const KEEP_LIVE = 5 * 60;

    /**
     * 获取基站导出的url
     *
     * @method GET
     * @data  devmac 探霸设备ID
     *        do LBS
     *        action export
     *        type txt/pdf/xls
     *
     * @return array|bool|mixed
     */
    public function export()
    {
        $deviceMac = $this->request->get['devmac'] ?? false;

        if (!$deviceMac) {
            return Common::error('未指定要获取的设备信息!');
        }

        if($this->redis->hGet($deviceMac,'cfgstatus') == 0)
            return  Common::error('设备不在线!');

        /**
         * 从缓存中获取到探霸地址、所连基站周边基站信息，并返回
         */
        /**
         * 同时给探霸发送 获取地址与获取所连基站信息 的命令(协议)
         * 不能同时发送，会导致发送失败!!!
         */
        $export = [];

        if (is_string($result = $this->parseLBSData($deviceMac))) {
            return Common::error($result);
        }

        $export['lbs'] = $result;

        // 等待上一个命令响应结束。


        if (!$result = $this->parseTBData($deviceMac, 1)) {
            return Common::error('查询探霸地址信息超时!');
        }

        $export['tb'] = $result;

        $type = $this->request->get['type'] ?? 'txt';

        $downloadUrl = '?do=LBS&key=' . md5($deviceMac) . '&action=export' . $type;

        $this->redis->set(md5($deviceMac), json_encode($export));

        return Common::success([
            'url' => $downloadUrl
        ]);
    }


    /**
     * 获取探霸及其周边基站信息
     *
     * @method GET
     * @data   devmac 探霸设备ID
     *         do  LBS
     *         action getTBLocation
     *
     * @return array|bool|mixed
     */
    public function getTBLocation()
    {
        $deviceMac = $this->request->get['devmac'] ?? false;

        if (!$deviceMac) {
            return Common::error('未指定要获取的设备信息!');
        }

        if($this->redis->hGet($deviceMac,'cfgstatus')==0)
            return  Common::error('设备不在线!');

        // 获取探霸地址
        $tbLocation = json_decode($this->redis->hGet($deviceMac,'location'), true);
        if (empty($tbLocation)) return Common::error('没有发现探霸位置信息');

        // 如果探霸地址获取错误，则使用探霸所连基站地址作为探霸所在地址。
        if (intval($tbLocation['longitude']) == 0 || intval($tbLocation['latitude']) == 0) {

            // 1. 获取探霸所连基站
            if (is_string($result = $this->parseLBSData($deviceMac))) {
                return Common::error($result);
            };

            $tbLocation = [
                'hightland' => '00000000',
                'latitude' => $result['lat'],
                'longitude' => $result['lon'],
                'time' => date('Y-m-d H:i:s'),
            ];
        }

        $lbsLocationLists['list'] = getCellocation($tbLocation['latitude'], $tbLocation['longitude']);
        $lbsLocationLists['time'] = $tbLocation['time'];

        return Common::success($lbsLocationLists);
    }


    /**
     * 获取探霸以及探霸所连基站信息
     *
     * @method GET
     * @data   devmac 探霸设备ID
     *         do  LBS
     *         action getLBSLocation
     */
    public function getLBSLocation()
    {
        $deviceMac = $this->request->get['devmac'] ?? false;

        if (!$deviceMac) {
            return Common::error('未指定要获取的设备信息!');
        }

        //dump($deviceMac, $this->redis->hGet($deviceMac,'cfgstatus'));
        if($this->redis->hGet($deviceMac,'cfgstatus')==0)
            return  Common::error('设备不在线!');

        // 1. 获取探霸所连基站
        if (is_string($result = $this->parseLBSData($deviceMac))) {
            return Common::error($result);
        };

        $lbsData = $result;

        //dump($lbsData);

        // 获取探霸地址
        $result = $this->parseTBData($deviceMac, 1);

        if (is_string($result)) {
            return Common::error($result);
        }

        // 如果探霸地址获取错误，则使用探霸所连基站地址作为探霸所在地址。
        if (intval($result['location']['longitude']) == 0 || intval($result['location']['latitude']) == 0) {
            $result['location'] = [
                'hightland' => '00000000',
                'latitude' => $lbsData['lat'],
                'longitude' => $lbsData['lon'],
                'time' => date('Y-m-d H:i:s'),
            ];
        }

        $lbsData['tanba'] = $result['location'];

        return Common::success($lbsData);
    }

    /**
     * 导出TXT格式
     *
     * @return mixed
     */
    public function exportTxt()
    {
        $key = $this->request->get['key'] ?? false;

        if (!$key) {
            return $this->response->end('缺乏下载参数!');
        }

        $data = json_decode($this->redis->get($key), true);

        if (!$data) {
            return $this->response->end('参数错误，或者时间太长请重新下载!');
        }

        $this->response->header('Content-Type', 'application/octet-stream;charset=utf-8');
        $this->response->header('Content-Disposition', 'attachment;filename=tanba.txt');

        // 探霸地址信息
        $txt = <<<TXT
探霸ID: {$data['tb']['deviceID']}
探霸的地址信息: 
    经度{$data['tb']['location']['latitude']}
    纬度{$data['tb']['location']['longitude']}
探霸所连基站信息:
    国家: {$data['lbs']['mcc_parse']}
    运营商: {$data['lbs']['mnc_parse']}
    LAC: {$data['lbs']['lac']}
    CI:  {$data['lbs']['ci']}
    类型: {$data['lbs']['type']}
    覆盖范围: {$data['lbs']['radius']}米
    经度: {$data['lbs']['lat']}
    纬度: {$data['lbs']['lon']}
    地址: {$data['lbs']['address']}
探霸周边基站信息:
TXT;

        foreach ($data['tb']['list'] as $key => $list) {
            $index = $key + 1;
            $data['lbs']['mcc'] = 460;
            $improve = LBS::improveParseData($data['lbs']);
            $txt .= <<<TXT
            
    ------------{$index}----------
    国家: {$improve['mcc_parse']}
    运营商: {$improve['mnc_parse']}
    LAC: {$list['lac']}
    CI:  {$list['ci']}
    类型: {$improve['type']}
    覆盖范围: {$list['acc']}米
    经度: {$list['location']['lat']}
    纬度: {$list['location']['lon']}
    地址: {$list['address']}
    --------------------------------
    
TXT;
        }

        $this->response->end($txt);
    }

    /**
     * 导出XLS格式
     */
    public function exportXls()
    {
        $key = $this->request->get['key'] ?? false;

        if (!$key) {
            return $this->response->end('缺乏下载参数!');
        }

        $data = json_decode($this->redis->get($key), true);

        if (!$data) {
            return $this->response->end('参数错误，或者时间太长请重新下载!');
        }

        $this->response->header('Content-Type', 'application/vnd.ms-excel');
        $this->response->header('Content-Disposition', 'attachment;filename=tanba.xls');


        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->setTitle('探霸');
        $sheet->setCellValue('A1', '探霸信息');
        $sheet->setCellValue('A2', '设备ID');
        $sheet->setCellValue('B2', '经度');
        $sheet->setCellValue('C2', '纬度');
        $sheet->setCellValue('A3', $data['tb']['deviceID']);
        $sheet->setCellValue('B3', $data['tb']['location']['latitude']);
        $sheet->setCellValue('C3', $data['tb']['location']['longitude']);

        // cell column
        $index = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'];
        // title
        $titleLists = ['国家', '运营商', 'LAC', 'CI', '类型', '覆盖范围', '经度', '纬度', '地址'];

        $sheet->setCellValue('A5', '探霸所连基站信息');

        // value key
        $keys = ['mcc_parse', 'mnc_parse', 'lac', 'ci', 'type', 'radius', 'lat', 'lon', 'address'];

        // 探霸所连基站信息
        foreach ($titleLists as $key => $value) {
            $sheet->setCellValue($index[$key] . '6', $value);
            $sheet->setCellValue($index[$key]  . '7', $data['lbs'][$keys[$key]]);
        }

        // 探霸周边基站信息

        $sheet->setCellValue('A9', '探霸周边基站信息');

        foreach ($titleLists as $key => $value) {
            $start = 10;
            $sheet->setCellValue($index[$key] . $start, $value);

            foreach ($data['tb']['list'] as $list) {
                ++$start;
                $list['mcc'] = 460;
                $list['mnc'] = sprintf('%02d', $list['mnc']);
                $list['lon'] = $list['location']['lon'];
                $list['lat'] = $list['location']['lat'];
                $list['radius'] = $list['acc'];

                $improve = LBS::improveParseData($list);
                $newArr = array_merge($list, $improve);
                $sheet->setCellValue($index[$key] . $start, $newArr[$keys[$key]]);
            }
        }

        $width = [20, 10, 10, 10, 7, 10, 10, 10, 80];
        foreach ($titleLists as $key => $value) {
            $sheet->getColumnDimension($index[$key])->setWidth($width[$key]);
        }



        $writer = IOFactory::createWriter($spreadsheet, 'Xls');
        ob_start();
        $writer->save('php://output');
        $this->response->end(ob_get_clean());
    }

    /**
     * 导出PDF格式
     */
    public function exportPdf()
    {
        $key = $this->request->get['key'] ?? false;

        if (!$key) {
            return $this->response->end('缺乏下载参数!');
        }

        $data = json_decode($this->redis->get($key), true);

        if (!$data) {
            return $this->response->end('参数错误，或者时间太长请重新下载!');
        }

        $pdf = new \TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);

// set document information
        $pdf->SetCreator(PDF_CREATOR);
        $pdf->SetAuthor('Nicola Asuni');
        $pdf->SetTitle('TCPDF Example 006');
        $pdf->SetSubject('TCPDF Tutorial');
        $pdf->SetKeywords('TCPDF, PDF, example, test, guide');

// set default header data
        //$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 006', PDF_HEADER_STRING);

// set header and footer fonts
        $pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
        $pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));

// set default monospaced font
        $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);

// set margins
        $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
        $pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
        $pdf->SetFooterMargin(PDF_MARGIN_FOOTER);

// set auto page breaks
        $pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);

// set image scale factor
        $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);

// ---------------------------------------------------------


        //设置字体 stsongstdlight支持中文
        $pdf->SetFont('stsongstdlight', '', 14);

        $html = <<<HTML
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
	</head>
	<body>
		<!--探霸信息-->
		<div>
			<h4>探霸信息</h4>
			<ul class="list-group">
				<li class="list-group-item">
					<b>探霸ID:</b>
					<span>{$data['tb']['deviceID']}</span>
				</li>
				<li class="list-group-item">
					<b>探霸的地址信息:</b>
					<span>探霸地址</span>
				</li>
				<li class="list-group-item">
					<b>探霸经度:</b>
					<span>{$data['tb']['location']['latitude']}</span>
				</li>
				<li class="list-group-item">
					<b>探霸维度:</b>
					<span>{$data['tb']['location']['longitude']}</span>
				</li>
			</ul>
		</div>
		<!--探霸信息-->
		
		<!--探霸链接基站信息-->
		<div>
			<h4>探霸所连接的基站信息</h4>
			<ul class="list-group">
				<li class="list-group-item">
					<b>国家:</b>
					<span>{$data['lbs']['mcc_parse']}</span>
				</li>
				<li class="list-group-item">
					<b>运营商:</b>
					<span>{$data['lbs']['mnc_parse']}</span>
				</li>
				<li class="list-group-item">
					<b>LAC:</b>
					<span>{$data['lbs']['lac']}</span>
				</li>
				<li class="list-group-item">
					<b>CI:</b>
					<span>{$data['lbs']['ci']}</span>
				</li>
				
				<li class="list-group-item">
					<b>类型:</b>
					<span>{$data['lbs']['type']}</span>
				</li>
				<li class="list-group-item">
					<b>覆盖范围:</b>
					<span>{$data['lbs']['radius']}米</span>
				</li>
				<li class="list-group-item">
					<b>经度:</b>
					<span>{$data['lbs']['lat']}</span>
				</li>
				<li class="list-group-item">
					<b>维度:</b>
					<span>{$data['lbs']['lon']}</span>
				</li>
				<li class="list-group-item">
					<b>地址:</b>
					<span>{$data['lbs']['address']}</span>
				</li>
			</ul>
		</div>
		<!--探霸链接基站信息-->
HTML;

        foreach ($data['tb']['list'] as $key => $list) {
            $data['lbs']['mcc'] = 460;
            $improve = LBS::improveParseData($data['lbs']);
            $html .= <<<HTML
            <div>
			<h4>探霸周边基站信息</h4>
			<ul class="list-group">
				<li class="list-group-item">
					<b>国家:</b>
					<span>{$improve['mcc_parse']}</span>
				</li>
				<li class="list-group-item">
					<b>运营商:</b>
					<span>{$improve['mnc_parse']}</span>
				</li>
				<li class="list-group-item">
					<b>LAC:</b>
					<span>{$list['lac']}</span>
				</li>
				<li class="list-group-item">
					<b>CI:</b>
					<span>{$list['ci']}</span>
				</li>
				
				<li class="list-group-item">
					<b>类型:</b>
					<span>{$improve['type']}</span>
				</li>
				<li class="list-group-item">
					<b>覆盖范围:</b>
					<span>{$list['acc']}米</span>
				</li>
				<li class="list-group-item">
					<b>经度:</b>
					<span>{$list['location']['lat']}</span>
				</li>
				<li class="list-group-item">
					<b>维度:</b>
					<span>{$list['location']['lon']}</span>
				</li>
				<li class="list-group-item">
					<b>地址:</b>
					<span>{$list['address']}</span>
				</li>
			</ul>
		</div>
HTML;
        }
        //第一页
        $pdf->AddPage();
        $pdf->writeHTML($html . '</body></html>', true, false, true, false, '');
        //$pdf->lastPage();
        $this->response->header('Content-Type', 'application/pdf');
        $this->response->header('Content-Disposition', 'attachment;filename=tanba.pdf');

        ob_start();
        $pdf->Output('123456.pdf', 'I');
        $this->response->end(ob_get_clean());
        exit;

    }

    /**
     * 解析探霸位置信息
     * 首先从缓存中获取探霸以及周边基站信息，如果不存在则发送指令给探霸进行获取
     * 探测成功后将信息保存到缓存中
     * 当获取不到探霸位置信息时返回false, 否则返回探霸以及周边的基站的位置信息
     * @param string $deviceMac 设备MAC地址
     * @param int $sleep
     * @return bool|mixed
     */
    protected function parseTBData($deviceMac, $sleep = 0)
    {
        if ($tbData = json_decode($this->redis->get($deviceMac . self::GET_TB_LOCATION), true)) {
            return $tbData;
        }

        if ($sleep) sleep($sleep);

        $getTBLocationCmd = Common::setCmd($this->request->fd, self::GET_TB_LOCATION, $deviceMac);
        $this->redis->lPush('command', $getTBLocationCmd);

        $loop = 0;
        while (true) {
            sleep(1);
            $result = json_decode($this->redis->get('httpCommandresult_' . $this->request->fd), true);

            //dump($result);
            if ($loop > 30) {
                return false;
            } elseif (!$result) {
                ++$loop;
                continue;
            } elseif ($result) {
                // 报错
                if (isset($result['errocode'])) {
                    return $result['errotext'];
                }
                $this->redis->del('httpCommandresult_' . $this->request->fd);
                $this->redis->setex($deviceMac . self::GET_TB_LOCATION, self::KEEP_LIVE, json_encode($result));
                return $result;
            }
        }
    }


    /**
     * 解析探霸所连基站信息，如果获取失败则返回字符串表示原因
     * 正确返回对应数据
     * @param $deviceMac
     * @return array|string
     */
    protected function parseLBSData($deviceMac)
    {
        if ($lbsData = json_decode($this->redis->get($deviceMac . self::GET_LBS_LOCATION), true)) {
            return $lbsData;
        }

        $getTBLocationCmd = Common::setCmd($this->request->fd, self::GET_LBS_LOCATION, $deviceMac);
        $this->redis->lPush('command', $getTBLocationCmd);

        $loop = 0;
        while (true) {
            sleep(1);
            $result = json_decode($this->redis->get('httpCcmdresult_locbase_' . $this->request->fd), true);

            if ($loop > 30) {
                return '查询探霸所连基站信息超时!';
            } elseif (!$result) {
                ++$loop;
                continue;
            } elseif ($result) {
                $this->redis->del('httpCcmdresult_locbase_' . $this->request->fd);

                if ($result == 2) {
                    return '查询失败!';
                } elseif ($result == 3) {
                    return '命令不支持!';
                } else {
                    $data = LBS::parse($result);
                }

                if (!$data) return '数据解析错误，请检查数据是否合法!';

                $this->redis->setex($deviceMac . self::GET_LBS_LOCATION, self::KEEP_LIVE, json_encode($data));
                return $data;
            }
        }
    }
}